package de.tum.in.eist.poll.client.views.widgets;

import com.google.gwt.i18n.client.NumberFormat;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.MouseWheelEvent;
import com.google.gwt.event.dom.client.MouseWheelHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.TextBox;


public class SpinBoxWidget extends Composite {
	private HorizontalPanel panel 	= new HorizontalPanel();
	private TextBox numberBox 		= new TextBox();
	private Button up 				= new Button("+");
	private Button down				= new Button("-");
	
	private Integer value           = 0;
	private Integer minimumValue	= 0;
	private Integer maximumValue 	= 0;
	
	/**
	 * A spin box is a Widget which is used to retrieve an POSITVE integer input
	 * from the user, bounded by a maximum value and a minimum value,
	 * where the maximum value must not be smaller than the minimum value.
	 * This constructor takes a default value, which must be in range
	 * given by maximum and minimum value.
	 * 
	 * Error recovery:
	 * If maximumValue < minimumValue is given their values are swapped.
	 * If default Value is out of bounds it is set to the minimum value.
	 * 
	 * @param minimumValue upper bound of the value
	 * @param maximumValue lower bound of the value
	 * @param initialValue default value to show at the beginning
	 */
	public SpinBoxWidget(Integer minimumValue, Integer maximumValue, Integer initialValue) {
		// error recovery
		if (minimumValue > maximumValue) {
			Integer tmp = maximumValue;
			maximumValue = minimumValue;
			minimumValue = tmp;
		}
		if (value < minimumValue || value > maximumValue) {
			value = minimumValue;
		}
		
		this.minimumValue = minimumValue;
		this.maximumValue = maximumValue;
		value = initialValue;
		refresh();
		
		// set up widgets
		numberBox.setWidth("40px");
		panel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
		up.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				setValue(getValue()+1);
			}
		});
		down.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				setValue(getValue()-1);
			}
		});
		// TODO: mark as extra behaviour
		numberBox.addMouseWheelHandler(new MouseWheelHandler() {
			@Override
			public void onMouseWheel(MouseWheelEvent event) {
				// TODO Auto-generated method stub
				Integer delta = event.getDeltaY();
				setValue(getValue()-delta);
			}
		});
		numberBox.addValueChangeHandler(new ValueChangeHandler<String>(){
			@Override
			public void onValueChange(ValueChangeEvent<String> event) {
				try {
					Integer newValue = (int)NumberFormat.getDecimalFormat().parse(numberBox.getText());
					setValue(newValue);
					refresh();
				} catch (NumberFormatException e) {
					refresh();
				}
			}
		});
		
		// add widgets to the layout
		panel.add(numberBox);
		panel.add(up);
		panel.add(down);
		
		initWidget(panel);
	}
	
	/**
	 * refreshes the display to show the current value
	 */
	public void refresh() {
		numberBox.setText(value.toString());
	}
	
	/**
	 * returns the current value
	 * @return current value
	 */
	public Integer getValue() {
		return value;
	}
	
	/**
	 * sets a new value
	 * @param newValue the new value to display
	 */
	public void setValue(Integer newValue) {
		if (newValue < minimumValue) {
			newValue = minimumValue;
		} else if (newValue > maximumValue) {
			newValue = maximumValue;
		}
		value = newValue;
		refresh();
	}
}
